Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[String] add LazyString to provide memoizing stringable objects #34298

Merged
merged 1 commit into from
Feb 3, 2020

Conversation

nicolas-grekas
Copy link
Member

@nicolas-grekas nicolas-grekas commented Nov 8, 2019

Q A
Branch? master
Bug fix? no
New feature? yes
Deprecations? no
Tickets -
License MIT
Doc PR -

Replaces #34190

The proposed LazyString class is a value object that can be used in type declarations of our libraries/apps.

Right now, when a method accepts or returns "strings|stringable-objects", the most accurate type declaration one can use is string|object (either in docblocks or in union types in PHP 8). The goal of LazyString is to allow one to use string|LazyString instead and gain type-accuracy, thus type-safety while doing so.

Another defining property of the proposed class is also that it memoizes the computed string value so that the computation happens only once.

Two factories are provided to create a LazyString instance:

  • LazyString::fromStringable($value): self -> turns any object with __toString() into a LazyString
  • LazyString::fromCallable($callback, ...$arguments): self -> delegates the computation of the string value to a callback (optionally calling it with arguments).

Two generic helpers are also provided to help deal with stringables:

  • LazyString::isStringable($value): bool -> checks whether a value can be safely cast to string, considering __toString() too. This replaces the boilerplate we all have to write currently (is_string($value) || is_scalar($value) || is_callable([$value, '__toString']))
  • LazyString::resolve($value): string -> casts a stringable value into a string. This is similar to the casting (string) operator or to strval(), but it throws a TypeError instead of a PHP notice when a non stringable is passed. This helps e.g. with code that enabled strict types and want to maintain compatibility with stringable objects.

An additional feature of LazyString instances is that they allow exceptions thrown from the wrapped __toString() methods or callbacks to be propagated. This requires having the ErrorHandler class from the Debug or ErrorHandler components registered as a PHP error handler (already the case for any Symfony apps by default). As a reminder, throwing from __toString() is not possible natively before PHP 7.4.

@nicolas-grekas nicolas-grekas added this to the 5.0 milestone Nov 8, 2019
@nicolas-grekas nicolas-grekas modified the milestones: 5.0, next Nov 8, 2019
@nicolas-grekas nicolas-grekas changed the title [String] add LazyString to the component [String] add LazyString to provide generic stringable objects Dec 2, 2019
@nicolas-grekas nicolas-grekas force-pushed the string-lazy branch 2 times, most recently from 04a8350 to 6bffaf5 Compare December 2, 2019 09:43
@nicolas-grekas
Copy link
Member Author

@symfony/mergers PR is ready. I updated the description to better explain what this does.

@nicolas-grekas nicolas-grekas changed the title [String] add LazyString to provide generic stringable objects [String] add LazyString to provide memoized stringable objects Jan 23, 2020
@nicolas-grekas nicolas-grekas changed the title [String] add LazyString to provide memoized stringable objects [String] add LazyString to provide memoizing stringable objects Jan 23, 2020
@nicolas-grekas nicolas-grekas force-pushed the string-lazy branch 3 times, most recently from 2670fac to 3fa9d12 Compare January 24, 2020 09:42
@fabpot
Copy link
Member

fabpot commented Feb 3, 2020

Thank you @nicolas-grekas.

fabpot added a commit that referenced this pull request Feb 3, 2020
…e objects (nicolas-grekas)

This PR was merged into the 5.1-dev branch.

Discussion
----------

[String] add LazyString to provide memoizing stringable objects

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | -
| License       | MIT
| Doc PR        | -

Replaces #34190

The proposed `LazyString` class is a value object that can be used in type declarations of our libraries/apps.

Right now, when a method accepts or returns "strings|stringable-objects", the most accurate type declaration one can use is `string|object` (either in docblocks or in union types in PHP 8). The goal of `LazyString` is to allow one to use `string|LazyString` instead and gain type-accuracy, thus type-safety while doing so.

Another defining property of the proposed class is also that it memoizes the computed string value so that the computation happens only once.

Two factories are provided to create a `LazyString` instance:
- `LazyString::fromStringable($value): self` -> turns any object with `__toString()` into a `LazyString`
- `LazyString::fromCallable($callback, ...$arguments): self` -> delegates the computation of the string value to a callback (optionally calling it with arguments).

Two generic helpers are also provided to help deal with stringables:
- `LazyString::isStringable($value): bool` -> checks whether a value can be safely cast to string, considering `__toString()` too. This replaces the boilerplate we all have to write currently (`is_string($value) || is_scalar($value) || is_callable([$value, '__toString'])`)
- `LazyString::resolve($value): string` -> casts a stringable value into a string. This is similar to the casting `(string)` operator or to `strval()`, but it throws a `TypeError` instead of a PHP notice when a non stringable is passed. This helps e.g. with code that enabled strict types and want to maintain compatibility with stringable objects.

An additional feature of `LazyString` instances is that they allow exceptions thrown from the wrapped `__toString()` methods or callbacks to be propagated. This requires having the `ErrorHandler` class from the `Debug` or `ErrorHandler` components registered as a PHP error handler (already the case for any Symfony apps by default). As a reminder, throwing from `__toString()` is not possible natively before PHP 7.4.

Commits
-------

4bb19c6 [String] add LazyString to provide generic stringable objects
@fabpot fabpot merged commit 4bb19c6 into symfony:master Feb 3, 2020
@nicolas-grekas nicolas-grekas deleted the string-lazy branch February 5, 2020 12:31
@nicolas-grekas nicolas-grekas modified the milestones: next, 5.1 May 4, 2020
@fabpot fabpot mentioned this pull request May 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants